package com.example.media.slice;

import com.example.media.ResourceTable;
import com.example.media.Utils;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.ability.DataAbilityHelper;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.global.resource.RawFileDescriptor;
import ohos.media.audio.AudioStreamInfo.*;
import ohos.app.Context;
import ohos.app.dispatcher.task.TaskPriority;
import ohos.data.dataability.DataAbilityPredicates;
import ohos.data.resultset.ResultSet;
import ohos.media.audio.*;
import ohos.media.common.Source;
import ohos.media.photokit.metadata.AVStorage;
import ohos.utils.net.Uri;

import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;

public class AudioAbilitySlice extends AbilitySlice implements Component.ClickedListener {
    // 音频渲染器
    private AudioRenderer mAudioRenderer = null;
    // 音频渲染器缓冲区大小
    private int mBufferSize = -1;

    private Button mBtnAudioPlay;
    private Button mBtnAudioPause;
    private Button mBtnAudioStop;
    private Button mBtnSoundResource;
    private Button mBtnSoundTone;
    private Button mBtnSoundSystem;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_audio);
        mBtnAudioPlay = (Button) findComponentById(ResourceTable.Id_btn_audio_play);
        mBtnAudioPlay.setClickedListener(this);
        mBtnAudioPause = (Button) findComponentById(ResourceTable.Id_btn_audio_pause);
        mBtnAudioPause.setClickedListener(this);
        mBtnAudioStop = (Button) findComponentById(ResourceTable.Id_btn_audio_stop);
        mBtnAudioStop.setClickedListener(this);
        mBtnSoundResource = (Button) findComponentById(ResourceTable.Id_btn_sound_resource);
        mBtnSoundResource.setClickedListener(this);
        mBtnSoundTone = (Button) findComponentById(ResourceTable.Id_btn_sound_tone);
        mBtnSoundTone.setClickedListener(this);
        mBtnSoundSystem = (Button) findComponentById(ResourceTable.Id_btn_sound_system);
        mBtnSoundSystem.setClickedListener(this);
    }

    @Override
    public void onClick(Component component) {
        // 播放音乐
        if (component.getId() == ResourceTable.Id_btn_audio_play) {
            // 如果音频渲染器为空,则创建音频渲染器
            if (mAudioRenderer == null) {
                // 音频流信息
                AudioStreamInfo audioStreamInfo = new Builder()
                        .sampleRate(44100) // 采样率
                        .audioStreamFlag(AudioStreamFlag.AUDIO_STREAM_FLAG_DIRECT_OUTPUT) // 直接输出
                        .encodingFormat(EncodingFormat.ENCODING_PCM_16BIT) // PCM格式
                        .channelMask(ChannelMask.CHANNEL_OUT_STEREO) // 双声道
                        .streamUsage(StreamUsage.STREAM_USAGE_MEDIA) // 媒体音乐播放用例
                        .build();
                // 音频渲染器缓冲区大小
                mBufferSize = AudioRenderer.getMinBufferSize(44100, // 采样率
                        EncodingFormat.ENCODING_PCM_16BIT,  // PCM格式
                        ChannelMask.CHANNEL_OUT_STEREO);  // 双声道
                // 音频渲染器信息
                AudioRendererInfo audioRendererInfo = new AudioRendererInfo.Builder()
                        .audioStreamInfo(audioStreamInfo) // 设置音频流信息
                        .bufferSizeInBytes(mBufferSize) // 缓冲区大小
                        .deviceId(obtainSpeaker().getId()) // 播放设备
                        .isOffload(false) // 是否一次性加载
                        .build();
                // 创建音频渲染器
                mAudioRenderer = new AudioRenderer(audioRendererInfo,
                        AudioRenderer.PlayMode.MODE_STREAM); // 数据流模式
            }
            // 开始播放
            mAudioRenderer.start();
            // 通过异步方法打开并读取音频文件
            getGlobalTaskDispatcher(TaskPriority.DEFAULT).asyncDispatch(() -> {
                try {
                    // 打开音频文件
                    FileDescriptor fd = getAudioMediaFileDescriptor("music.wav");
                    // 开始读取文件(音频)流
                    FileInputStream is = new FileInputStream(fd);
                    byte[] buf = new byte[mBufferSize];
                    int length = 0;
                    while ((length = is.read(buf)) != -1) {
                        if (mAudioRenderer == null) {
                            break;
                        }
                        // 读取到音频流后,直接装入音频渲染器进行处理
                        mAudioRenderer.write(buf, 0, length);
                    }
                    // 读取完毕后关闭文件(音频)流
                    is.close();
                } catch (Exception e) {
                    Utils.log(e.getLocalizedMessage());
                }
            });
        }
        // 暂停音乐
        if (component.getId() == ResourceTable.Id_btn_audio_pause) {
            if (mAudioRenderer != null) {
                mAudioRenderer.pause();
            }
        }
        // 停止音乐
        if (component.getId() == ResourceTable.Id_btn_audio_stop) {
            if (mAudioRenderer != null) {
                mAudioRenderer.stop();
                mAudioRenderer.release();
            }
        }

        // 播放短音:音频资源
        if (component.getId() == ResourceTable.Id_btn_sound_resource) {
            try {
                // 创建SoundPlayer对象
                SoundPlayer soundPlayer = new SoundPlayer();
                // 获取播放短音的文件描述
                RawFileDescriptor fd = getResourceManager()
                        .getRawFileEntry("resources/rawfile/prompt.wav")
                        .openRawFileDescriptor();
                // 创建自定义短音
                int soundId = soundPlayer.createSound(fd);
                // 播放自定义短音
                soundPlayer.play(soundId);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        // 播放短音:tone音效
        if (component.getId() == ResourceTable.Id_btn_sound_tone) {
            // 创建SoundPlayer对象
            SoundPlayer soundPlayer = new SoundPlayer();
            // 创建Tone音效
            soundPlayer.createSound(ToneDescriptor.ToneType.DTMF_1, 500);
            // 播放Tone音效
            soundPlayer.play();
        }
        // 播放短音:系统音效
        if (component.getId() == ResourceTable.Id_btn_sound_system) {
            // 创建SoundPlayer对象
            SoundPlayer soundPlayer = new SoundPlayer("package");
            // 播放键盘按下标准音效
            soundPlayer.playSound(SoundPlayer.SoundType.KEYPRESS_STANDARD, 1.0f);
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        // 关闭AbilitySlice时,需要将音频渲染器关闭并释放,否则音频播放将无法控制
        if (mAudioRenderer != null) {
            mAudioRenderer.stop();
            mAudioRenderer.release();
        }
    }

    /**
     * 获取扬声器对象
     * @return
     */
    private AudioDeviceDescriptor obtainSpeaker() {
        // 扬声器设备
        AudioDeviceDescriptor speaker = null;
        // 获取音频播放设备
        AudioDeviceDescriptor[] devices = AudioManager
                .getDevices(AudioDeviceDescriptor.DeviceFlag.OUTPUT_DEVICES_FLAG);
        if (devices == null || devices.length == 0) {
            return null;
        }
        // 获取扬声器设备
        for (AudioDeviceDescriptor device : devices) {
            if (AudioDeviceDescriptor.DeviceType.SPEAKER == device.getType()) {
                speaker = device;
                break;
            }
        }
        return speaker;
    }

    /**
     * 获取音频媒体文件
     *
     * @param name 文件名称
     * @return 文件描述FileDescriptor对象
     */
    public FileDescriptor getAudioMediaFileDescriptor(String name) {
        DataAbilityHelper helper = DataAbilityHelper.creator(this);
        ResultSet rs = null;
        FileDescriptor fileDescriptor = null;
        try {
            DataAbilityPredicates predicates =
                    new DataAbilityPredicates(
                            "_display_name = '" + name + "'");
            rs = helper.query(AVStorage.Audio.Media.EXTERNAL_DATA_ABILITY_URI,
                    new String[]{AVStorage.Audio.Media.ID},
                    predicates);
            if (rs != null && rs.goToFirstRow()) {
                int mediaId = rs.getInt(0);
                Uri uri = Uri.appendEncodedPathToUri(
                        AVStorage.Audio.Media.EXTERNAL_DATA_ABILITY_URI,
                        "" + mediaId);
                fileDescriptor = helper.openFile(uri, "r");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (rs != null) {
                rs.close();
            }
        }
        return fileDescriptor;
    }

}
